﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common.Utilities;

namespace Workflows.Components.Entities.Relations.InferredAssociations
{
    [Serializable]
    public class Tree
    {
        private int _Id;
        /// <summary></summary>
        public int Id
        {
            get
            {
                return this._Id;
            }
            set
            {
                this._Id = value;
            }
        }

        private string _Label;
        /// <summary></summary>
        public string Label
        {
            get
            {
                return this._Label;
            }
            set
            {
                this._Label = value;
            }
        }

        private Tree _Parent;
        /// <summary></summary>
        public Tree Parent
        {
            get
            {
                return this._Parent;
            }
            set
            {
                this._Parent = value;
            }
        }

        private Dictionary<Tree, double> _Branches;
        /// <summary>child branch -> association (0,1] to self</summary>
        public Dictionary<Tree, double> Branches
        {
            get
            {
                return this._Branches;
            }
            set
            {
                this._Branches = value;
            }
        }

        private Dictionary<EntityMetaData, double> _Leaves;
        /// <summary>child entity -> degree of association (0,1]</summary>
        public Dictionary<EntityMetaData, double> Leaves
        {
            get
            {
                return this._Leaves;
            }
            set
            {
                this._Leaves = value;
            }
        }

        public Tree(int id, string label)
        {
            this._Id = id;
            this._Label = label;
            this._Parent = null;
            this._Branches = new Dictionary<Tree, double>();
            this._Leaves = new Dictionary<EntityMetaData, double>();
        }

        public Tree(int id, string label, Tree parent, double distanceToParent)
            : this(id, label)
        {
            this._Parent = parent;
            if (this._Parent != null)
                this._Parent.AddBranch(this, distanceToParent);
        }

        protected void AddBranch(Tree branch, double distance)
        {
            if (this._Branches == null)
                this._Branches = new Dictionary<Tree, double>();
            if (!this._Branches.ContainsKey(branch))
                this._Branches.Add(branch, distance);
        }

        public int GetEntityCount()
        {
            int entityCount = 0;
            if (this._Leaves != null && this._Leaves.Count > 0)
                entityCount = this._Leaves.Count;

            if (this._Branches != null && this._Branches.Count > 0)
            {
                foreach (Tree branch in this._Branches.Keys)
                {
                    entityCount += branch.GetEntityCount();
                }
            }
            return entityCount;
        }

        public double GetAverageDiameter()
        {
            List<double> diameters = new List<double>();
            if (this._Leaves != null && this._Leaves.Count > 0)
            {
                foreach (EntityMetaData entity in this._Leaves.Keys)
                {
                    diameters.Add(1 - this._Leaves[entity]);
                }
            }
            if (this._Branches != null && this._Branches.Count > 0)
            {
                foreach (Tree branch in this._Branches.Keys)
                {
                    diameters.Add(1 - this._Branches[branch]);
                }
            }
            return StatsUtil.GetAverage(diameters).Value;
        }
    }
}
